#include "Ink_inet.h"
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>

bool
IpEntry::is_ipv4(const sockaddr *addr)
{
	return addr->sa_family == AF_INET;
}

bool
IpEntry::is_ipv6(const sockaddr *addr)
{
	return addr->sa_family == AF_INET6;
}

bool
IpEntry::is_valid() const
{
	return _family != AF_UNSPEC;
}

IpEntry &
IpEntry::assign()
{
	if(_family == AF_INET)
	{
		sockaddr_in *addr4 = (sockaddr_in *)malloc(sizeof(struct sockaddr_in));
		memset(addr4, 0, sizeof(struct sockaddr_in));
		addr4->sin_family = _family;
		addr4->sin_addr.s_addr = _ip.ip4;
		addr4->sin_port = _port;
		_addr = (sockaddr *)addr4;
	}else if(_family == AF_INET6){
		sockaddr_in6 *addr6 = (sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6));
		memset(addr6, 0, sizeof(struct sockaddr_in6));
		addr6->sin6_family = _family;
		addr6->sin6_addr = _ip.ip6;
		addr6->sin6_port = _port;
		_addr = (sockaddr *)addr6;
	}else{
		_family = AF_UNSPEC;
	}
}

void
IpEntry::init(int family, const char *ip, int port)
{
	_family = family;

	if(_family == AF_INET)
	{
		inet_pton(AF_INET, ip, &_ip.ip4);
		_port = htons(port);
	}else if(_family == AF_INET6)
	{
		inet_pton(AF_INET6, ip, &_ip.ip6);
		port = htons(port);
	}

	assign();
}

void
IpEntry::init(sockaddr *addr)
{
	if(is_ipv4(addr))
	{
		_family = AF_INET;
		_ip.ip4 = ((sockaddr_in *)addr)->sin_addr.s_addr;
		_port = htons(((sockaddr_in *)addr)->sin_port);
	}else if(is_ipv6(addr))
	{
		_family = AF_INET6;
		_ip.ip6 = ((sockaddr_in6 *)addr)->sin6_addr;
		_port = htons(((sockaddr_in6 *)addr)->sin6_port);
	}else{
		_family = AF_UNSPEC;
	}

	assign();
}

void
IpEntry::init(in_addr_t ip, int port)
{
	_family = AF_INET;
	_ip.ip4 = htonl(ip);
	_port = htons(port);

	assign();
}

void
IpEntry::init(in6_addr ip, int port)
{
	_family = AF_INET6;
	_ip.ip6 = ip;
	_port = htons(port);

	assign();
}

void
IpEntry::init(const IpEntry &entry)
{
	_family = entry._family;
	_ip = entry._ip;
	_port = entry._port;

	assign();
}

IpEntry &
IpEntry::operator=(const IpEntry & entry)
{
	if(this == &entry)
		return *this;

	_family = entry._family;
	_ip = entry._ip;
	_port = entry._port;

	assign();

	return *this;
}

IpEntry::IpEntry() : _addr(NULL)
{
	_family = AF_UNSPEC;
}

IpEntry::~IpEntry()
{
	if(_addr != 0)
		free(_addr);
}

int
IpEntry::get_port_h()
{
	return ntohs(this->_port);
}

int
IpEntry::get_port_n()
{
	return this->_port;
}

int
IpEntry::get_family()
{
	return this->_family;
}

bool
IpEntry::get_ip_string(char *ip, int len)
{
	if(is_ipv4(_addr))
	{
		return inet_ntop(AF_INET,(void *)&((sockaddr_in *)_addr)->sin_addr, ip, len) ? true : false;
	}else if(is_ipv6(_addr))
	{
		return inet_ntop(AF_INET6,(void *)&((sockaddr_in6 *)_addr)->sin6_addr, ip, len);
	}

	return false;
}

sockaddr *
IpEntry::get_addr()
{
	return _addr;
}
